home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / amiga / ixmlb920.lha / stdio_2 / rcs / vfprintf.c,v < prev    next >
Text File  |  1992-07-04  |  23KB  |  1,014 lines

  1. head    1.1;
  2. access;
  3. symbols
  4.     version39-41:1.1;
  5. locks;
  6. comment    @ * @;
  7.  
  8.  
  9. 1.1
  10. date    92.06.08.15.10.10;    author mwild;    state Exp;
  11. branches;
  12. next    ;
  13.  
  14.  
  15. desc
  16. @initial checkin
  17. @
  18.  
  19.  
  20. 1.1
  21. log
  22. @Initial revision
  23. @
  24. text
  25. @/*-
  26.  * Copyright (c) 1990 The Regents of the University of California.
  27.  * All rights reserved.
  28.  *
  29.  * This code is derived from software contributed to Berkeley by
  30.  * Chris Torek.
  31.  *
  32.  * Redistribution and use in source and binary forms, with or without
  33.  * modification, are permitted provided that the following conditions
  34.  * are met:
  35.  * 1. Redistributions of source code must retain the above copyright
  36.  *    notice, this list of conditions and the following disclaimer.
  37.  * 2. Redistributions in binary form must reproduce the above copyright
  38.  *    notice, this list of conditions and the following disclaimer in the
  39.  *    documentation and/or other materials provided with the distribution.
  40.  * 3. All advertising materials mentioning features or use of this software
  41.  *    must display the following acknowledgement:
  42.  *    This product includes software developed by the University of
  43.  *    California, Berkeley and its contributors.
  44.  * 4. Neither the name of the University nor the names of its contributors
  45.  *    may be used to endorse or promote products derived from this software
  46.  *    without specific prior written permission.
  47.  *
  48.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  49.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  50.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  51.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  52.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  53.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  54.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  55.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  56.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  57.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  58.  * SUCH DAMAGE.
  59.  */
  60.  
  61. #if defined(LIBC_SCCS) && !defined(lint)
  62. static char sccsid[] = "@@(#)vfprintf.c    5.47 (Berkeley) 3/22/91";
  63. #endif /* LIBC_SCCS and not lint */
  64.  
  65. /*
  66.  * Actual printf innards.
  67.  *
  68.  * This code is large and complicated...
  69.  */
  70.  
  71. #define KERNEL
  72. #include "ixemul.h"
  73.  
  74. #include <math.h>
  75. #include <stdio.h>
  76. #include <string.h>
  77. #if __STDC__
  78. #include <stdarg.h>
  79. #else
  80. #include <varargs.h>
  81. #endif
  82. #include "local.h"
  83. #include "fvwrite.h"
  84.  
  85. /*
  86.  * Define FLOATING_POINT to get floating point.
  87.  * Define CSH to get a csh-specific version (grr).
  88.  */
  89. #ifndef CSH
  90. #define    FLOATING_POINT
  91. #endif
  92.  
  93. /* end of configuration stuff */
  94.  
  95.  
  96. #ifdef CSH
  97. /*
  98.  * C shell hacks.  Ick, gag.
  99.  */
  100. #undef BUFSIZ
  101. #include "sh.h"
  102.  
  103. #if __STDC__
  104. int
  105. printf(const char *fmt, ...) {
  106.     FILE f;
  107.     va_list ap;
  108.     int ret;
  109.  
  110.     va_start(ap, fmt);
  111.     f._flags = __SWR;
  112.     f._write = NULL;
  113.     ret = vfprintf(&f, fmt, ap);
  114.     va_end(ap);
  115.     return ret;
  116. }
  117. #else
  118. int
  119. printf(fmt, args)
  120.     char *fmt;
  121. {
  122.     FILE f;
  123.  
  124.     f._flags = __SWR;
  125.     f._write = NULL;
  126.     return (vfprintf(&f, fmt, &args));
  127. }
  128. #endif
  129.  
  130. int
  131. __sprint(fp, uio)
  132.     FILE *fp;
  133.     register struct __suio *uio;
  134. {
  135.     register char *p;
  136.     register int n, ch, iovcnt;
  137.     register struct __siov *iov;
  138.  
  139.     /* must allow sprintf to work, might as well allow others too */
  140.     if (fp->_write || fp->_flags & __SSTR) {
  141.         if (uio->uio_resid == 0) {
  142.             uio->uio_iovcnt = 0;
  143.             return (0);
  144.         }
  145.         n = __sfvwrite(fp, uio);
  146.         uio->uio_resid = 0;
  147.         uio->uio_iovcnt = 0;
  148.         return (n);
  149.     }
  150.     iov = uio->uio_iov;
  151.     for (iovcnt = uio->uio_iovcnt; --iovcnt >= 0; iov++) {
  152.         for (p = iov->iov_base, n = iov->iov_len; --n >= 0;) {
  153. #ifdef CSHPUTCHAR
  154.             ch = *p++;
  155.             CSHPUTCHAR;    /* this horrid macro uses `ch' */
  156. #else
  157. #undef putchar
  158.             putchar(*p++);
  159. #endif
  160.         }
  161.     }
  162.     uio->uio_resid = 0;
  163.     uio->uio_iovcnt = 0;
  164.     return (0);
  165. }
  166.  
  167. #else /* CSH */
  168.  
  169. /*
  170.  * Flush out all the vectors defined by the given uio,
  171.  * then reset it so that it can be reused.
  172.  */
  173. static int
  174. __sprint(fp, uio)
  175.     FILE *fp;
  176.     register struct __suio *uio;
  177. {
  178.     register int err;
  179.  
  180.     if (uio->uio_resid == 0) {
  181.         uio->uio_iovcnt = 0;
  182.         return (0);
  183.     }
  184.     err = __sfvwrite(fp, uio);
  185.     uio->uio_resid = 0;
  186.     uio->uio_iovcnt = 0;
  187.     return (err);
  188. }
  189.  
  190. /*
  191.  * Helper function for `fprintf to unbuffered unix file': creates a
  192.  * temporary buffer.  We only work on write-only files; this avoids
  193.  * worries about ungetc buffers and so forth.
  194.  */
  195. static int
  196. __sbprintf(fp, fmt, ap)
  197.     register FILE *fp;
  198.     const char *fmt;
  199.     va_list ap;
  200. {
  201.     int ret;
  202.     FILE fake;
  203.     unsigned char buf[BUFSIZ];
  204.  
  205.     /* copy the important variables */
  206.     fake._flags = fp->_flags & ~__SNBF;
  207.     fake._file = fp->_file;
  208.     fake._cookie = fp->_cookie;
  209.     fake._write = fp->_write;
  210.  
  211.     /* set up the buffer */
  212.     fake._bf._base = fake._p = buf;
  213.     fake._bf._size = fake._w = sizeof(buf);
  214.     fake._lbfsize = 0;    /* not actually used, but Just In Case */
  215.  
  216.     /* do the work, then copy any error status */
  217.     ret = vfprintf(&fake, fmt, ap);
  218.     if (ret >= 0 && fflush(&fake))
  219.         ret = EOF;
  220.     if (fake._flags & __SERR)
  221.         fp->_flags |= __SERR;
  222.     return (ret);
  223. }
  224.  
  225. #endif /* CSH */
  226.  
  227.  
  228. #ifdef FLOATING_POINT
  229. #include "floatio.h"
  230.  
  231. #define    BUF        (MAXEXP+MAXFRACT+1)    /* + decimal point */
  232. #define    DEFPREC        6
  233.  
  234. static int cvt();
  235.  
  236. #else /* no FLOATING_POINT */
  237.  
  238. #define    BUF        40
  239.  
  240. #endif /* FLOATING_POINT */
  241.  
  242.  
  243. /*
  244.  * Macros for converting digits to letters and vice versa
  245.  */
  246. #define    to_digit(c)    ((c) - '0')
  247. #define is_digit(c)    ((unsigned)to_digit(c) <= 9)
  248. #define    to_char(n)    ((n) + '0')
  249.  
  250. /*
  251.  * Flags used during conversion.
  252.  */
  253. #define    LONGINT        0x01        /* long integer */
  254. #define    LONGDBL        0x02        /* long double; unimplemented */
  255. #define    SHORTINT    0x04        /* short integer */
  256. #define    ALT        0x08        /* alternate form */
  257. #define    LADJUST        0x10        /* left adjustment */
  258. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  259. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  260.  
  261. int
  262. vfprintf(fp, fmt0, ap)
  263.     FILE *fp;
  264.     const char *fmt0;
  265. #if tahoe
  266.  register /* technically illegal, since we do not know what type va_list is */
  267. #endif
  268.     va_list ap;
  269. {
  270.     register char *fmt;    /* format string */
  271.     register int ch;    /* character from fmt */
  272.     register int n;        /* handy integer (short term usage) */
  273.     register char *cp;    /* handy char pointer (short term usage) */
  274.     register struct __siov *iovp;/* for PRINT macro */
  275.     register int flags;    /* flags as above */
  276.     int ret;        /* return value accumulator */
  277.     int width;        /* width from format (%8d), or 0 */
  278.     int prec;        /* precision from format (%.3d), or -1 */
  279.     char sign;        /* sign prefix (' ', '+', '-', or \0) */
  280. #ifdef FLOATING_POINT
  281.     char softsign;        /* temporary negative sign for floats */
  282.     double _double;        /* double precision arguments %[eEfgG] */
  283.     int fpprec;        /* `extra' floating precision in [eEfgG] */
  284. #endif
  285.     u_long _ulong;        /* integer arguments %[diouxX] */
  286.     enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
  287.     int dprec;        /* a copy of prec if [diouxX], 0 otherwise */
  288.     int fieldsz;        /* field size expanded by sign, etc */
  289.     int realsz;        /* field size expanded by dprec */
  290.     int size;        /* size of converted field or string */
  291.     char *xdigs;        /* digits for [xX] conversion */
  292. #define NIOV 8
  293.     struct __suio uio;    /* output information: summary */
  294.     struct __siov iov[NIOV];/* ... and individual io vectors */
  295.     char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  296.     char ox[2];        /* space for 0x hex-prefix */
  297.  
  298.     /*
  299.      * Choose PADSIZE to trade efficiency vs size.  If larger
  300.      * printf fields occur frequently, increase PADSIZE (and make
  301.      * the initialisers below longer).
  302.      */
  303. #define    PADSIZE    16        /* pad chunk size */
  304.     static char blanks[PADSIZE] =
  305.      {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
  306.     static char zeroes[PADSIZE] =
  307.      {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
  308.  
  309.     /*
  310.      * BEWARE, these `goto error' on error, and PAD uses `n'.
  311.      */
  312. #define    PRINT(ptr, len) { \
  313.     iovp->iov_base = (ptr); \
  314.     iovp->iov_len = (len); \
  315.     uio.uio_resid += (len); \
  316.     iovp++; \
  317.     if (++uio.uio_iovcnt >= NIOV) { \
  318.         if (__sprint(fp, &uio)) \
  319.             goto error; \
  320.         iovp = iov; \
  321.     } \
  322. }
  323. #define    PAD(howmany, with) { \
  324.     if ((n = (howmany)) > 0) { \
  325.         while (n > PADSIZE) { \
  326.             PRINT(with, PADSIZE); \
  327.             n -= PADSIZE; \
  328.         } \
  329.         PRINT(with, n); \
  330.     } \
  331. }
  332. #define    FLUSH() { \
  333.     if (uio.uio_resid && __sprint(fp, &uio)) \
  334.         goto error; \
  335.     uio.uio_iovcnt = 0; \
  336.     iovp = iov; \
  337. }
  338.  
  339.     /*
  340.      * To extend shorts properly, we need both signed and unsigned
  341.      * argument extraction methods.
  342.      */
  343. #define    SARG() \
  344.     (flags&LONGINT ? va_arg(ap, long) : \
  345.         flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
  346.         (long)va_arg(ap, int))
  347. #define    UARG() \
  348.     (flags&LONGINT ? va_arg(ap, u_long) : \
  349.         flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
  350.         (u_long)va_arg(ap, u_int))
  351.  
  352. #ifndef CSH
  353.     /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
  354.     if (!fp || cantwrite(fp))
  355.         return (EOF);
  356.  
  357.     /* optimise fprintf(stderr) (and other unbuffered Unix files) */
  358.     if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
  359.         fp->_file >= 0)
  360.         return (__sbprintf(fp, fmt0, ap));
  361. #endif /* CSH */
  362.  
  363.     fmt = (char *)fmt0;
  364.     uio.uio_iov = iovp = iov;
  365.     uio.uio_resid = 0;
  366.     uio.uio_iovcnt = 0;
  367.     ret = 0;
  368.  
  369.     /*
  370.      * Scan the format for conversions (`%' character).
  371.      */
  372.     for (;;) {
  373.         for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
  374.             /* void */;
  375.         if ((n = fmt - cp) != 0) {
  376.             PRINT(cp, n);
  377.             ret += n;
  378.         }
  379.         if (ch == '\0')
  380.             goto done;
  381.         fmt++;        /* skip over '%' */
  382.  
  383.         flags = 0;
  384.         dprec = 0;
  385. #ifdef FLOATING_POINT
  386.         fpprec = 0;
  387. #endif
  388.         width = 0;
  389.         prec = -1;
  390.         sign = '\0';
  391.  
  392. rflag:        ch = *fmt++;
  393. reswitch:    switch (ch) {
  394.         case ' ':
  395.             /*
  396.              * ``If the space and + flags both appear, the space
  397.              * flag will be ignored.''
  398.              *    -- ANSI X3J11
  399.              */
  400.             if (!sign)
  401.                 sign = ' ';
  402.             goto rflag;
  403.         case '#':
  404.             flags |= ALT;
  405.             goto rflag;
  406.         case '*':
  407.             /*
  408.              * ``A negative field width argument is taken as a
  409.              * - flag followed by a positive field width.''
  410.              *    -- ANSI X3J11
  411.              * They don't exclude field widths read from args.
  412.              */
  413.             if ((width = va_arg(ap, int)) >= 0)
  414.                 goto rflag;
  415.             width = -width;
  416.             /* FALLTHROUGH */
  417.         case '-':
  418.             flags |= LADJUST;
  419.             goto rflag;
  420.         case '+':
  421.             sign = '+';
  422.             goto rflag;
  423.         case '.':
  424.             if ((ch = *fmt++) == '*') {
  425.                 n = va_arg(ap, int);
  426.                 prec = n < 0 ? -1 : n;
  427.                 goto rflag;
  428.             }
  429.             n = 0;
  430.             while (is_digit(ch)) {
  431.                 n = 10 * n + to_digit(ch);
  432.                 ch = *fmt++;
  433.             }
  434.             prec = n < 0 ? -1 : n;
  435.             goto reswitch;
  436.         case '0':
  437.             /*
  438.              * ``Note that 0 is taken as a flag, not as the
  439.              * beginning of a field width.''
  440.              *    -- ANSI X3J11
  441.              */
  442.             flags |= ZEROPAD;
  443.             goto rflag;
  444.         case '1': case '2': case '3': case '4':
  445.         case '5': case '6': case '7': case '8': case '9':
  446.             n = 0;
  447.             do {
  448.                 n = 10 * n + to_digit(ch);
  449.                 ch = *fmt++;
  450.             } while (is_digit(ch));
  451.             width = n;
  452.             goto reswitch;
  453. #ifdef FLOATING_POINT
  454.         case 'L':
  455.             flags |= LONGDBL;
  456.             goto rflag;
  457. #endif
  458.         case 'h':
  459.             flags |= SHORTINT;
  460.             goto rflag;
  461.         case 'l':
  462.             flags |= LONGINT;
  463.             goto rflag;
  464.         case 'c':
  465.             *(cp = buf) = va_arg(ap, int);
  466.             size = 1;
  467.             sign = '\0';
  468.             break;
  469.         case 'D':
  470.             flags |= LONGINT;
  471.             /*FALLTHROUGH*/
  472.         case 'd':
  473.         case 'i':
  474.             _ulong = SARG();
  475.             if ((long)_ulong < 0) {
  476.                 _ulong = -_ulong;
  477.                 sign = '-';
  478.             }
  479.             base = DEC;
  480.             goto number;
  481. #ifdef FLOATING_POINT
  482.         case 'e':
  483.         case 'E':
  484.         case 'f':
  485.         case 'g':
  486.         case 'G':
  487.             _double = va_arg(ap, double);
  488.             /* do this before tricky precision changes */
  489.             if (isinf(_double)) {
  490.                 if (_double < 0)
  491.                     sign = '-';
  492.                 cp = "Inf";
  493.                 size = 3;
  494.                 break;
  495.             }
  496.             if (isnan(_double)) {
  497.                 cp = "NaN";
  498.                 size = 3;
  499.                 break;
  500.             }
  501.             /*
  502.              * don't do unrealistic precision; just pad it with
  503.              * zeroes later, so buffer size stays rational.
  504.              */
  505.             if (prec > MAXFRACT) {
  506.                 if (ch != 'g' && ch != 'G' || (flags&ALT))
  507.                     fpprec = prec - MAXFRACT;
  508.                 prec = MAXFRACT;
  509.             } else if (prec == -1)
  510.                 prec = DEFPREC;
  511.             /*
  512.              * cvt may have to round up before the "start" of
  513.              * its buffer, i.e. ``intf("%.2f", (double)9.999);'';
  514.              * if the first character is still NUL, it did.
  515.              * softsign avoids negative 0 if _double < 0 but
  516.              * no significant digits will be shown.
  517.              */
  518.             cp = buf;
  519.             *cp = '\0';
  520.             size = cvt(_double, prec, flags, &softsign, ch,
  521.                 cp, buf + sizeof(buf));
  522.             if (softsign)
  523.                 sign = '-';
  524.             if (*cp == '\0')
  525.                 cp++;
  526.             break;
  527. #endif /* FLOATING_POINT */
  528.         case 'n':
  529.             if (flags & LONGINT)
  530.                 *va_arg(ap, long *) = ret;
  531.             else if (flags & SHORTINT)
  532.                 *va_arg(ap, short *) = ret;
  533.             else
  534.                 *va_arg(ap, int *) = ret;
  535.             continue;    /* no output */
  536.         case 'O':
  537.             flags |= LONGINT;
  538.             /*FALLTHROUGH*/
  539.         case 'o':
  540.             _ulong = UARG();
  541.             base = OCT;
  542.             goto nosign;
  543.         case 'p':
  544.             /*
  545.              * ``The argument shall be a pointer to void.  The
  546.              * value of the pointer is converted to a sequence
  547.              * of printable characters, in an implementation-
  548.              * defined manner.''
  549.              *    -- ANSI X3J11
  550.              */
  551.             /* NOSTRICT */
  552.             _ulong = (u_long)va_arg(ap, void *);
  553.             base = HEX;
  554.             xdigs = "0123456789abcdef";
  555.             flags |= HEXPREFIX;
  556.             ch = 'x';
  557.             goto nosign;
  558.         case 's':
  559.             if ((cp = va_arg(ap, char *)) == NULL)
  560.                 cp = "(null)";
  561.             if (prec >= 0) {
  562.                 /*
  563.                  * can't use strlen; can only look for the
  564.                  * NUL in the first `prec' characters, and
  565.                  * strlen() will go further.
  566.                  */
  567.                 char *p = memchr(cp, 0, prec);
  568.  
  569.                 if (p != NULL) {
  570.                     size = p - cp;
  571.                     if (size > prec)
  572.                         size = prec;
  573.                 } else
  574.                     size = prec;
  575.             } else
  576.                 size = strlen(cp);
  577.             sign = '\0';
  578.             break;
  579.         case 'U':
  580.             flags |= LONGINT;
  581.             /*FALLTHROUGH*/
  582.         case 'u':
  583.             _ulong = UARG();
  584.             base = DEC;
  585.             goto nosign;
  586.         case 'X':
  587.             xdigs = "0123456789ABCDEF";
  588.             goto hex;
  589.         case 'x':
  590.             xdigs = "0123456789abcdef";
  591. hex:            _ulong = UARG();
  592.             base = HEX;
  593.             /* leading 0x/X only if non-zero */
  594.             if (flags & ALT && _ulong != 0)
  595.                 flags |= HEXPREFIX;
  596.  
  597.             /* unsigned conversions */
  598. nosign:            sign = '\0';
  599.             /*
  600.              * ``... diouXx conversions ... if a precision is
  601.              * specified, the 0 flag will be ignored.''
  602.              *    -- ANSI X3J11
  603.              */
  604. number:            if ((dprec = prec) >= 0)
  605.                 flags &= ~ZEROPAD;
  606.  
  607.             /*
  608.              * ``The result of converting a zero value with an
  609.              * explicit precision of zero is no characters.''
  610.              *    -- ANSI X3J11
  611.              */
  612.             cp = buf + BUF;
  613.             if (_ulong != 0 || prec != 0) {
  614.                 /*
  615.                  * unsigned mod is hard, and unsigned mod
  616.                  * by a constant is easier than that by
  617.                  * a variable; hence this switch.
  618.                  */
  619.                 switch (base) {
  620.                 case OCT:
  621.                     do {
  622.                         *--cp = to_char(_ulong & 7);
  623.                         _ulong >>= 3;
  624.                     } while (_ulong);
  625.                     /* handle octal leading 0 */
  626.                     if (flags & ALT && *cp != '0')
  627.                         *--cp = '0';
  628.                     break;
  629.  
  630.                 case DEC:
  631.                     /* many numbers are 1 digit */
  632.                     while (_ulong >= 10) {
  633.                         *--cp = to_char(_ulong % 10);
  634.                         _ulong /= 10;
  635.                     }
  636.                     *--cp = to_char(_ulong);
  637.                     break;
  638.  
  639.                 case HEX:
  640.                     do {
  641.                         *--cp = xdigs[_ulong & 15];
  642.                         _ulong >>= 4;
  643.                     } while (_ulong);
  644.                     break;
  645.  
  646.                 default:
  647.                     cp = "bug in vfprintf: bad base";
  648.                     size = strlen(cp);
  649.                     goto skipsize;
  650.                 }
  651.             }
  652.             size = buf + BUF - cp;
  653.         skipsize:
  654.             break;
  655.         default:    /* "%?" prints ?, unless ? is NUL */
  656.             if (ch == '\0')
  657.                 goto done;
  658.             /* pretend it was %c with argument ch */
  659.             cp = buf;
  660.             *cp = ch;
  661.             size = 1;
  662.             sign = '\0';
  663.             break;
  664.         }
  665.  
  666.         /*
  667.          * All reasonable formats wind up here.  At this point,
  668.          * `cp' points to a string which (if not flags&LADJUST)
  669.          * should be padded out to `width' places.  If
  670.          * flags&ZEROPAD, it should first be prefixed by any
  671.          * sign or other prefix; otherwise, it should be blank
  672.          * padded before the prefix is emitted.  After any
  673.          * left-hand padding and prefixing, emit zeroes
  674.          * required by a decimal [diouxX] precision, then print
  675.          * the string proper, then emit zeroes required by any
  676.          * leftover floating precision; finally, if LADJUST,
  677.          * pad with blanks.
  678.          */
  679.  
  680.         /*
  681.          * compute actual size, so we know how much to pad.
  682.          * fieldsz excludes decimal prec; realsz includes it
  683.          */
  684. #ifdef FLOATING_POINT
  685.         fieldsz = size + fpprec;
  686. #else
  687.         fieldsz = size;
  688. #endif
  689.         if (sign)
  690.             fieldsz++;
  691.         else if (flags & HEXPREFIX)
  692.             fieldsz += 2;
  693.         realsz = dprec > fieldsz ? dprec : fieldsz;
  694.  
  695.         /* right-adjusting blank padding */
  696.         if ((flags & (LADJUST|ZEROPAD)) == 0)
  697.             PAD(width - realsz, blanks);
  698.  
  699.         /* prefix */
  700.         if (sign) {
  701.             PRINT(&sign, 1);
  702.         } else if (flags & HEXPREFIX) {
  703.             ox[0] = '0';
  704.             ox[1] = ch;
  705.             PRINT(ox, 2);
  706.         }
  707.  
  708.         /* right-adjusting zero padding */
  709.         if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  710.             PAD(width - realsz, zeroes);
  711.  
  712.         /* leading zeroes from decimal precision */
  713.         PAD(dprec - fieldsz, zeroes);
  714.  
  715.         /* the string or number proper */
  716.         PRINT(cp, size);
  717.  
  718. #ifdef FLOATING_POINT
  719.         /* trailing f.p. zeroes */
  720.         PAD(fpprec, zeroes);
  721. #endif
  722.  
  723.         /* left-adjusting padding (always blank) */
  724.         if (flags & LADJUST)
  725.             PAD(width - realsz, blanks);
  726.  
  727.         /* finally, adjust ret */
  728.         ret += width > realsz ? width : realsz;
  729.  
  730.         FLUSH();    /* copy out the I/O vectors */
  731.     }
  732. done:
  733.     FLUSH();
  734. error:
  735.     return (__sferror(fp) ? EOF : ret);
  736.     /* NOTREACHED */
  737. }
  738.  
  739. #ifdef FLOATING_POINT
  740. #include <math.h>
  741.  
  742. static char *exponent();
  743. static char *round();
  744.  
  745. static int
  746. cvt(number, prec, flags, signp, fmtch, startp, endp)
  747.     double number;
  748.     register int prec;
  749.     int flags;
  750.     char *signp;
  751.     int fmtch;
  752.     char *startp, *endp;
  753. {
  754.     register char *p, *t;
  755.     register double fract;
  756.     int dotrim, expcnt, gformat;
  757.     double integer, tmp;
  758.  
  759.     dotrim = expcnt = gformat = 0;
  760.     if (number < 0) {
  761.         number = -number;
  762.         *signp = '-';
  763.     } else
  764.         *signp = 0;
  765.  
  766.     fract = modf(number, &integer);
  767.  
  768.     /* get an extra slot for rounding. */
  769.     t = ++startp;
  770.  
  771.     /*
  772.      * get integer portion of number; put into the end of the buffer; the
  773.      * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  774.      */
  775.     for (p = endp - 1; integer; ++expcnt) {
  776.         tmp = modf(integer / 10, &integer);
  777.         *p-- = to_char((int)((tmp + .01) * 10));
  778.     }
  779.     switch (fmtch) {
  780.     case 'f':
  781.         /* reverse integer into beginning of buffer */
  782.         if (expcnt)
  783.             for (; ++p < endp; *t++ = *p);
  784.         else
  785.             *t++ = '0';
  786.         /*
  787.          * if precision required or alternate flag set, add in a
  788.          * decimal point.
  789.          */
  790.         if (prec || flags&ALT)
  791.             *t++ = '.';
  792.         /* if requires more precision and some fraction left */
  793.         if (fract) {
  794.             if (prec)
  795.                 do {
  796.                     fract = modf(fract * 10, &tmp);
  797.                     *t++ = to_char((int)tmp);
  798.                 } while (--prec && fract);
  799.             if (fract)
  800.                 startp = round(fract, (int *)NULL, startp,
  801.                     t - 1, (char)0, signp);
  802.         }
  803.         for (; prec--; *t++ = '0');
  804.         break;
  805.     case 'e':
  806.     case 'E':
  807. eformat:    if (expcnt) {
  808.             *t++ = *++p;
  809.             if (prec || flags&ALT)
  810.                 *t++ = '.';
  811.             /* if requires more precision and some integer left */
  812.             for (; prec && ++p < endp; --prec)
  813.                 *t++ = *p;
  814.             /*
  815.              * if done precision and more of the integer component,
  816.              * round using it; adjust fract so we don't re-round
  817.              * later.
  818.              */
  819.             if (!prec && ++p < endp) {
  820.                 fract = 0;
  821.                 startp = round((double)0, &expcnt, startp,
  822.                     t - 1, *p, signp);
  823.             }
  824.             /* adjust expcnt for digit in front of decimal */
  825.             --expcnt;
  826.         }
  827.         /* until first fractional digit, decrement exponent */
  828.         else if (fract) {
  829.             /* adjust expcnt for digit in front of decimal */
  830.             for (expcnt = -1;; --expcnt) {
  831.                 fract = modf(fract * 10, &tmp);
  832.                 if (tmp)
  833.                     break;
  834.             }
  835.             *t++ = to_char((int)tmp);
  836.             if (prec || flags&ALT)
  837.                 *t++ = '.';
  838.         }
  839.         else {
  840.             *t++ = '0';
  841.             if (prec || flags&ALT)
  842.                 *t++ = '.';
  843.         }
  844.         /* if requires more precision and some fraction left */
  845.         if (fract) {
  846.             if (prec)
  847.                 do {
  848.                     fract = modf(fract * 10, &tmp);
  849.                     *t++ = to_char((int)tmp);
  850.                 } while (--prec && fract);
  851.             if (fract)
  852.                 startp = round(fract, &expcnt, startp,
  853.                     t - 1, (char)0, signp);
  854.         }
  855.         /* if requires more precision */
  856.         for (; prec--; *t++ = '0');
  857.  
  858.         /* unless alternate flag, trim any g/G format trailing 0's */
  859.         if (gformat && !(flags&ALT)) {
  860.             while (t > startp && *--t == '0');
  861.             if (*t == '.')
  862.                 --t;
  863.             ++t;
  864.         }
  865.         t = exponent(t, expcnt, fmtch);
  866.         break;
  867.     case 'g':
  868.     case 'G':
  869.         /* a precision of 0 is treated as a precision of 1. */
  870.         if (!prec)
  871.             ++prec;
  872.         /*
  873.          * ``The style used depends on the value converted; style e
  874.          * will be used only if the exponent resulting from the
  875.          * conversion is less than -4 or greater than the precision.''
  876.          *    -- ANSI X3J11
  877.          */
  878.         if (expcnt > prec || !expcnt && fract && fract < .0001) {
  879.             /*
  880.              * g/G format counts "significant digits, not digits of
  881.              * precision; for the e/E format, this just causes an
  882.              * off-by-one problem, i.e. g/G considers the digit
  883.              * before the decimal point significant and e/E doesn't
  884.              * count it as precision.
  885.              */
  886.             --prec;
  887.             fmtch -= 2;        /* G->E, g->e */
  888.             gformat = 1;
  889.             goto eformat;
  890.         }
  891.         /*
  892.          * reverse integer into beginning of buffer,
  893.          * note, decrement precision
  894.          */
  895.         if (expcnt)
  896.             for (; ++p < endp; *t++ = *p, --prec);
  897.         else
  898.             *t++ = '0';
  899.         /*
  900.          * if precision required or alternate flag set, add in a
  901.          * decimal point.  If no digits yet, add in leading 0.
  902.          */
  903.         if (prec || flags&ALT) {
  904.             dotrim = 1;
  905.             *t++ = '.';
  906.         }
  907.         else
  908.             dotrim = 0;
  909.         /* if requires more precision and some fraction left */
  910.         if (fract) {
  911.             if (prec) {
  912.                 do {
  913.                     fract = modf(fract * 10, &tmp);
  914.                     *t++ = to_char((int)tmp);
  915.                 } while(!tmp);
  916.                 while (--prec && fract) {
  917.                     fract = modf(fract * 10, &tmp);
  918.                     *t++ = to_char((int)tmp);
  919.                 }
  920.             }
  921.             if (fract)
  922.                 startp = round(fract, (int *)NULL, startp,
  923.                     t - 1, (char)0, signp);
  924.         }
  925.         /* alternate format, adds 0's for precision, else trim 0's */
  926.         if (flags&ALT)
  927.             for (; prec--; *t++ = '0');
  928.         else if (dotrim) {
  929.             while (t > startp && *--t == '0');
  930.             if (*t != '.')
  931.                 ++t;
  932.         }
  933.     }
  934.     return (t - startp);
  935. }
  936.  
  937. static char *
  938. round(fract, exp, start, end, ch, signp)
  939.     double fract;
  940.     int *exp;
  941.     register char *start, *end;
  942.     char ch, *signp;
  943. {
  944.     double tmp;
  945.  
  946.     if (fract)
  947.         (void)modf(fract * 10, &tmp);
  948.     else
  949.         tmp = to_digit(ch);
  950.     if (tmp > 4)
  951.         for (;; --end) {
  952.             if (*end == '.')
  953.                 --end;
  954.             if (++*end <= '9')
  955.                 break;
  956.             *end = '0';
  957.             if (end == start) {
  958.                 if (exp) {    /* e/E; increment exponent */
  959.                     *end = '1';
  960.                     ++*exp;
  961.                 }
  962.                 else {        /* f; add extra digit */
  963.                 *--end = '1';
  964.                 --start;
  965.                 }
  966.                 break;
  967.             }
  968.         }
  969.     /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  970.     else if (*signp == '-')
  971.         for (;; --end) {
  972.             if (*end == '.')
  973.                 --end;
  974.             if (*end != '0')
  975.                 break;
  976.             if (end == start)
  977.                 *signp = 0;
  978.         }
  979.     return (start);
  980. }
  981.  
  982. static char *
  983. exponent(p, exp, fmtch)
  984.     register char *p;
  985.     register int exp;
  986.     int fmtch;
  987. {
  988.     register char *t;
  989.     char expbuf[MAXEXP];
  990.  
  991.     *p++ = fmtch;
  992.     if (exp < 0) {
  993.         exp = -exp;
  994.         *p++ = '-';
  995.     }
  996.     else
  997.         *p++ = '+';
  998.     t = expbuf + MAXEXP;
  999.     if (exp > 9) {
  1000.         do {
  1001.             *--t = to_char(exp % 10);
  1002.         } while ((exp /= 10) > 9);
  1003.         *--t = to_char(exp);
  1004.         for (; t < expbuf + MAXEXP; *p++ = *t++);
  1005.     }
  1006.     else {
  1007.         *p++ = '0';
  1008.         *p++ = to_char(exp);
  1009.     }
  1010.     return (p);
  1011. }
  1012. #endif /* FLOATING_POINT */
  1013. @
  1014.